package com.jjc.android.util

import android.content.Context
import com.jjc.android.App
import java.io.Serializable
import kotlin.properties.ReadWriteProperty
import kotlin.reflect.KProperty

const val SPFileName = "userConfig.preferences"
const val SPFileNameApp = "com.jjc.android.preferences"
/**
 * 使用defSP的话key为""在SPUtil中key会赋值成变量名
 * 所以一般用这个
 */
inline fun <reified R, T> R.defSP(default: T) = SPUtil("", default)

/**
 * 指定key用这个
 */
inline fun <reified R, T> R.defSP(key: String, default: T) = SPUtil(key, default)

inline fun <reified R, T> R.defACache(key: String, default: T) = ACacheIn(key, default)

inline fun <reified R, T> R.defSPApp(key: String, default: T) = SPUtil(key, default, SPFileNameApp)

val mACache:ACache by lazy {
    ACache.get(App.getContext())
}

class ACacheIn<T>(val key: String, val defValue: T) : ReadWriteProperty<Any?, T> {


    override fun getValue(thisRef: Any?, property: KProperty<*>): T {
        val temKey = if (key.isEmpty()) property.name else key
        return when (defValue) {
            is String -> mACache.getAsString(temKey)
            is Serializable -> mACache.getAsObject(temKey)
            else -> throw IllegalArgumentException("type error")
        }.let {
            it ?: defValue
        } as T
    }

    override fun setValue(thisRef: Any?, property: KProperty<*>, value: T) {
        val temKey = if (key.isEmpty()) property.name else key
        with(mACache) {
            when (value) {
                is String -> put(temKey, value)
                is Serializable -> put(temKey, value)
                else -> throw IllegalArgumentException("type error")
            }
        }
    }
}

class SPUtil<T>(val key: String, val defValue: T, val fileName: String = SPFileName) : ReadWriteProperty<Any?, T> {
    val sp by lazy {
        App.getContext().getSharedPreferences(fileName, Context.MODE_PRIVATE)
    }

    override fun getValue(thisRef: Any?, property: KProperty<*>): T {
        val temKey = if (key.isEmpty()) property.name else key
        return when (defValue) {
            is String -> sp.getString(temKey, defValue)
            is Boolean -> sp.getBoolean(temKey, defValue)
            is Int -> sp.getInt(temKey, defValue)
            is Float -> sp.getFloat(temKey, defValue)
            is Long -> sp.getLong(temKey, defValue)
            else -> throw IllegalArgumentException("type error")
        } as T
    }

    override fun setValue(thisRef: Any?, property: KProperty<*>, value: T) {
        val temKey = if (key.isEmpty()) property.name else key
        with(sp.edit()) {
            when (value) {
                is String -> putString(temKey, value)
                is Boolean -> putBoolean(temKey, value)
                is Int -> putInt(temKey, value)
                is Float -> putFloat(temKey, value)
                is Long -> putLong(temKey, value)
                else -> throw IllegalArgumentException("type error")
            }
            commit()
        }
    }
}

fun cleanSP(fileName: String = SPFileName) {
    App.getContext().getSharedPreferences(fileName, Context.MODE_PRIVATE).edit().clear().commit()
}

val globalSp by lazy {
    App.getContext().getSharedPreferences(SPFileName, Context.MODE_PRIVATE)
}

inline fun <T> putSpu(key: String, value: T) {
    with(globalSp.edit()) {
        when (value) {
            is String -> putString(key, value)
            is Boolean -> putBoolean(key, value)
            is Int -> putInt(key, value)
            is Float -> putFloat(key, value)
            is Long -> putLong(key, value)
            else -> throw IllegalArgumentException("类型错误")
        }
        commit()
    }
}

inline fun <T> getSpu(key: String, defValue: T): T {
    return when (defValue) {
        is String -> globalSp.getString(key, defValue)
        is Boolean -> globalSp.getBoolean(key, defValue)
        is Int -> globalSp.getInt(key, defValue)
        is Float -> globalSp.getFloat(key, defValue)
        is Long -> globalSp.getLong(key, defValue)
        else -> throw IllegalArgumentException("类型错误")
    } as T
}

fun cleanSPByKeyContanins(contaninNameKey: String, ignoreCase: Boolean = false) {
    val editor = globalSp.edit()
    var find = false
    globalSp.all.forEach {
        if(!it.key.isNullOrEmpty()&&it.key.contains(contaninNameKey,ignoreCase)){
            editor.remove(it.key)
            find = true
        }
    }
    if(find){
        editor.apply()
    }
}
